package com.sinochem.yunlian.ship.common.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.sinochem.yunlian.ship.common.constant.UCHttpRequest;
import com.sinochem.yunlian.ship.common.enums.ResponseCode;
import com.sinochem.yunlian.ship.common.exception.BaseException;
import com.sinochem.yunlian.ship.common.msg.UCResponse;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class HttpClientService {

	private Logger LOG = LoggerFactory.getLogger(getClass());

	@Setter
	@Getter
	private int connectTimeout = 30000;

	/**
	 *
     * post 请求
	 * @param method
     * @param requestParamMap
	 * @param headerParamMap
     * @param clazz
     * @param <T>
     * @return
     */
	protected <T> T sendRequestPost(String uri,String method,
			Map<String, String> requestParamMap, Map<String,String> headerParamMap, Class<T> clazz) {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpClient = HttpClients.createDefault();
		T response = null;
		String url = uri + method;
		HttpPost httpPost = new HttpPost(url);
		try {
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(connectTimeout)
					.setConnectTimeout(connectTimeout)
					.setConnectionRequestTimeout(connectTimeout).build();

			StringEntity httpEntity = new StringEntity(JSON.toJSONString(requestParamMap), Consts.UTF_8);
			httpPost.setEntity(httpEntity);
			httpPost.setConfig(requestConfig);
			//添加 Http Post Header
			for (String key : headerParamMap.keySet()) {
				httpPost.setHeader(key, headerParamMap
						.get(key));
			}
			httpPost.addHeader("Content-Type", "application/json");
			CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
			try {
				HttpEntity entity = httpResponse.getEntity();
				try {
					if (null != entity) {
						response = JSON.parseObject(EntityUtils.toString(
								httpResponse.getEntity(), Consts.UTF_8), clazz);
					}
				} catch (Exception e) {
					LOG.error(e.getMessage(), e);
					throw new BaseException("接口返回数据格式有误，转化失败!", ResponseCode.UC_ERROR_DATAFORMAT.getCode());
				} finally {
					if (entity != null) {
						entity.getContent().close();
					}
				}
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
			} finally {
				if (httpResponse != null) {
					httpResponse.close();
				}
			}
			if (LOG.isInfoEnabled()) {
				LOG.info("HttpClient request post url: " + url);
				LOG.info("HttpClient request param: " + JSON.toJSONString(requestParamMap));
				LOG.info("HttpClient response: " + JSON.toJSONString(response));
			}
		} catch (ClientProtocolException e) {
			LOG.error("ClientProtocolException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} catch (IOException e) {
			LOG.error("IOException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} finally {
			httpPost.releaseConnection();
		}
		return response;
	}

	/**
	 *
	 * @author: chengyiping
	 * @description:  发送普通get请求  url ? 拼接
	 * @date: Created in 2018/3/27 15:00
	 * @modified By :
	 * @version:
	*/
	public <T> T sendRequestGet(String uri,String method,
									  Map<String, String> requestParamMap, Map<String,String> headerParamMap, Class<T> clazz) {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpClient = HttpClients.createDefault();
		T response = null;
     	try {
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(connectTimeout)
					.setConnectTimeout(connectTimeout)
					.setConnectionRequestTimeout(connectTimeout).build();
			List<NameValuePair> getParams = new ArrayList<NameValuePair>();
			for (String key : requestParamMap.keySet()) {
				getParams.add(new BasicNameValuePair(key, requestParamMap
						.get(key)));
			}
			// 参数转换为字符串.
			String paramsStr = EntityUtils.toString(new UrlEncodedFormEntity(getParams, Consts.UTF_8));
			String url = uri +  method + "?" + paramsStr;
			// 创建HttpGet.
			HttpGet httpGet = new HttpGet(url);

			//添加 Http Get Header
			for (String key : headerParamMap.keySet()) {
				httpGet.setHeader(key, headerParamMap
						.get(key));
			}

			httpGet.setConfig(requestConfig);
			// 执行get请求.
			CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
			try {
				// 获取响应实体
				HttpEntity entity = httpResponse.getEntity();
				// 打印响应状态
				System.out.println(httpResponse.getStatusLine());
				try {
					if (null != entity) {
						response = JSON.parseObject(EntityUtils.toString(
								httpResponse.getEntity(), Consts.UTF_8), clazz);
					}
				} catch (Exception e) {
					LOG.error(e.getMessage(), e);
					throw new BaseException("接口返回数据格式有误，转化失败!", ResponseCode.UC_ERROR_DATAFORMAT.getCode());
				} finally {
					if (entity != null) {
						entity.getContent().close();
					}
				}
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
			} finally {
				httpResponse.close();
				httpGet.releaseConnection();
			}
			if (LOG.isInfoEnabled()) {
				LOG.info("HttpClient request get url: " + url);
				LOG.info("HttpClient response: " + JSON.toJSONString(response));
			}
		}  catch (ClientProtocolException e) {
			LOG.error("ClientProtocolException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} catch (IOException e) {
			LOG.error("IOException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		}
		return response;
	}
	public String sendRequestGetForGkw(String uri,String method,
								Map<String, String> requestParamMap, Map<String,String> headerParamMap) {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpClient = HttpClients.createDefault();
		String response = null;
		try {
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(connectTimeout)
					.setConnectTimeout(connectTimeout)
					.setConnectionRequestTimeout(connectTimeout).build();
			List<NameValuePair> getParams = new ArrayList<NameValuePair>();
			for (String key : requestParamMap.keySet()) {
				getParams.add(new BasicNameValuePair(key, requestParamMap
						.get(key)));
			}
			// 参数转换为字符串.
			String paramsStr = EntityUtils.toString(new UrlEncodedFormEntity(getParams, Consts.UTF_8));
			String url = uri +  method + "?" + paramsStr;
			// 创建HttpGet.
			HttpGet httpGet = new HttpGet(url);

			//添加 Http Get Header
			for (String key : headerParamMap.keySet()) {
				httpGet.setHeader(key, headerParamMap
						.get(key));
			}

			httpGet.setConfig(requestConfig);
			// 执行get请求.
			CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
			try {
				// 获取响应实体
				HttpEntity entity = httpResponse.getEntity();
				// 打印响应状态
				System.out.println(httpResponse.getStatusLine());
				try {
					if (null != entity) {
						 response = EntityUtils.toString(entity);// 返回json格式：

					}
				} catch (Exception e) {
					LOG.error(e.getMessage(), e);
					throw new BaseException("接口返回数据格式有误，转化失败!", ResponseCode.UC_ERROR_DATAFORMAT.getCode());
				} finally {
					if (entity != null) {
						entity.getContent().close();
					}
				}
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
			} finally {
				httpResponse.close();
				httpGet.releaseConnection();
			}
			if (LOG.isInfoEnabled()) {
				LOG.info("HttpClient request get url: " + url);
				LOG.info("HttpClient response: " + response);
			}
		}  catch (ClientProtocolException e) {
			LOG.error("ClientProtocolException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} catch (IOException e) {
			LOG.error("IOException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		}
		return response;
	}
	/**
	 *
	 * @author: chengyiping
	 * @description:  发送rest get请求
	 * @date: Created in 2018/3/27 15:00
	 * @modified By :
	 * @version:
	 */
	public <T> T sendRequestRestGet(String uri, String method, Map<String,String> headerParamMap, Class<T> clazz) {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpClient = HttpClients.createDefault();
		T response = null;
		String url = uri + method;
		// 创建HttpGet.
		HttpGet httpGet = new HttpGet(url);
		try {
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(connectTimeout)
					.setConnectTimeout(connectTimeout)
					.setConnectionRequestTimeout(connectTimeout).build();
			httpGet.setConfig(requestConfig);

			//添加 Http Get Header
			for (String key : headerParamMap.keySet()) {
				httpGet.setHeader(key, headerParamMap
						.get(key));
			}

			// 执行get请求.
			CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
			try {
				// 获取响应实体
				HttpEntity entity = httpResponse.getEntity();
				// 打印响应状态
				System.out.println(httpResponse.getStatusLine());
				try {
					if (null != entity) {
						response = JSON.parseObject(EntityUtils.toString(
								httpResponse.getEntity(), Consts.UTF_8), clazz);
					}
				} catch (Exception e) {
					LOG.error(e.getMessage(), e);
					throw new BaseException("接口返回数据格式有误，转化失败!", ResponseCode.UC_ERROR_DATAFORMAT.getCode());
				} finally {
					if (entity != null) {
						entity.getContent().close();
					}
				}
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
				throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
			} finally {
				httpResponse.close();
			}
			if (LOG.isInfoEnabled()) {
				LOG.info("HttpClient request rest get url: " + url);
				LOG.info("HttpClient response: " + JSON.toJSONString(response));
			}
		}  catch (ClientProtocolException e) {
			LOG.error("ClientProtocolException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} catch (IOException e) {
			LOG.error("IOException", e);
			throw new BaseException("接口调用失败，请核实接口、网络!", ResponseCode.UC_ERROR_HTTPTIMEOUT.getCode());
		} finally {
			httpGet.releaseConnection();
		}
		return response;
	}

	public <T> T callHttpClientPost(String uri,String method, Map<String, String> requestParamMap, Map<String,String> headerParamMap, Class<T> clazz) {
		return sendRequestPost(uri,method, requestParamMap,headerParamMap,clazz);
	}

	public <T> T callHttpClientPost(String uri,String method, Map<String,String> headerParamMap, Class<T> clazz) {
		return sendRequestPost(uri,method, null,headerParamMap,clazz);
	}

	public <T> T callHttpClientGet(String uri,String method, Map<String, String> requestParamMap, Map<String,String> headerParamMap, Class<T> clazz) {
		return sendRequestGet(uri,method,requestParamMap,headerParamMap,clazz);
	}

	public <T> T callHttpClientRestGet(String uri,String method, Map<String,String> headerParamMap, Class<T> clazz) {
		return sendRequestRestGet(uri,method,headerParamMap,clazz);
	}

	/**
	 * 调用 requestUCAPI 使用前台web、app 接口、含请求参数token
	 *
	 * @param method
	 * @param requestParamMap
	 * @param hearderParamMap
	 * @return
	 */
	public UCResponse requestUCAPI(String apiUrl, String token , String requestType, String method , Map<String,String> requestParamMap, Map<String,String> hearderParamMap){
		UCResponse ucResponse = null;
		try {
			if(requestType.equals(UCHttpRequest.UC_HTTP_POST)){
				ucResponse = this.callHttpClientPost(apiUrl, method, requestParamMap, hearderParamMap, UCResponse.class);
			} else if(requestType.equals(UCHttpRequest.UC_HTTP_GET)){
				ucResponse = this.callHttpClientGet(apiUrl, method, requestParamMap, hearderParamMap, UCResponse.class);
			} else if(requestType.equals(UCHttpRequest.UC_HTTP_RESTGET)){
				ucResponse = this.callHttpClientRestGet(apiUrl, method, hearderParamMap, UCResponse.class);
			} else {
				LOG.info("调用用户中心接口失败,接口url:{},接口token:{},用户中心不支持该请求操作!", apiUrl + method, token, requestType);
			}
			return ucResponse;
		} catch(BaseException be){
			LOG.error("调用用户中心接口失败,接口url:{},接口token:{},异常栈:{},请核查!", apiUrl + method, token, be);
			return null;
		} catch(Exception e){
			LOG.error("调用用户中心接口返回数据格式有误,接口url:{},接口token:{},异常栈:{},请核查!", apiUrl + method, token, e);
			return null;
		}
	}

	/**
	 * 调用 requestUCAPI 适用于 consumer 调用、免token
	 *
	 * @param method
	 * @param requestParamMap
	 * @param hearderParamMap
	 * @return
	 */
	public UCResponse requestUCAPI(String apiUrl, String requestType, String method, Map<String,String> requestParamMap, Map<String,String> hearderParamMap){
		UCResponse ucResponse = null;
		try {
			if(requestType.equals(UCHttpRequest.UC_HTTP_POST)){
				ucResponse = this.callHttpClientPost(apiUrl, method, requestParamMap, hearderParamMap, UCResponse.class);
			} else if(requestType.equals(UCHttpRequest.UC_HTTP_GET)){
				ucResponse = this.callHttpClientGet(apiUrl, method, requestParamMap, hearderParamMap, UCResponse.class);
			} else if(requestType.equals(UCHttpRequest.UC_HTTP_RESTGET)){
				ucResponse = this.callHttpClientRestGet(apiUrl, method, hearderParamMap, UCResponse.class);
			} else {
				LOG.info("调用用户中心接口失败,接口url:{},用户中心不支持该请求操作!", apiUrl + method, requestType);
			}
			return ucResponse;
		} catch(BaseException be){
			LOG.error("调用用户中心接口失败,接口url:{},异常栈:{},请核查!", apiUrl + method, be);
			return null;
		} catch(Exception e){
			LOG.error("调用用户中心接口返回数据格式有误,接口url:{},异常栈:{},请核查!", apiUrl + method, e);
			return null;
		}
	}

}
